"""

Телеграмм бот, английских слов
    
https://docs.aiogram.dev/en/latest/

********************    Linux commands  ********************
#!/usr/bin/env python3
#!/usr/bin/python3
# chmod +x 073.py

ps ax | grep 073.py
pkill -f 073.py

apt install python3.8-venv

apt-get update && apt-get upgrade -y
apt install python3-pip
pip3 install -U aiogram


apt-get update --fix-missing
************************************************************

"""
####################################################################################################


# import os
# import time
import random
import sqlite3
import keyboards as kb

from en_words import en                             #  словарь английских слов
from en_words import tr                             #  словарь звуки (транскрипция)
from en_words import ru                             #  словарь перевод на русском

from config import token_en1000 as token
from config import admin_id as admin_id

# aiogram imports
from aiogram import Bot, types
from aiogram.dispatcher import Dispatcher
from aiogram.utils import executor
from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton

####################################################################################################
print('EN1000 app starting')
print('==================================================')

# bot = Bot(token=token, disable_web_page_preview=True)
bot = Bot(token=token, parse_mode="HTML", disable_web_page_preview=True,)
dp = Dispatcher(bot)

len_en = len(en)-1
len_tr = len(tr)-1
len_ru = len(ru)-1

bd_name = "en1000Users.sqlite"

user_en_true = {}

help_msg = """<b>Помощь</b>

1️⃣ для начала, идем в главное меню /start 
2️⃣ выбираем  <i>EN to RU или RU to EN </i>
3️⃣ получаем слово на выбранном языке
4️⃣ стараемся выбрать правильный перевод
5️⃣ получил ✅ - молодчинка
6️⃣ получил ‼️ - попробуй еще раз

Удачного изучения!
У тебя обязательно все получится. 
Иногда, просто, нужно немного больше времени и упорства на изучение! 😉

--------------------

Связаться с разработчиком - <a href="https://yarinat.ru/links?utm_source=yoomoney&utm_medium=tg_bot&utm_campaign=EN1000">https://yarinat.ru </a>

--------------------

Накинуть автору на кофе - <a href="https://yoomoney.ru/to/410011617713875?utm_source=yoomoney&utm_medium=tg_bot&utm_campaign=EN1000"> https://yoomoney.ru/to/410011617713875 </a>

--------------------
"""


####################################################################################################
# class Lesson:
#     def __init__(self, en_true):
#         self.en_true = en_true


####################################################################################################

@dp.callback_query_handler(text=["en_to_ru_test"])
async def call_back_en(call: types.CallbackQuery):
    """
    This handler will be called when user sends `/en_to_ru_test` cb command
    """
    global user_en_true
    user_en_true.update({call.message.chat.id: True})
    en_true = user_en_true.get(call.message.chat.id) # что ты здесь делаешь ? тебя же можно в функцию проверки сразу закинуть

    print(f"EN_to_ru_test                en_true = {en_true}")
    
    # инициализация тестирования
    print('==================================================   en_to_ru_test')
    print(call)
    print("==================================================")
    msg = "Начинаем тестирование! \nEN to RU"
    await bot.send_message(call.message.chat.id, msg)

    # генерируем случайное слово из словоря EN
    msg = f"{en[random.randint(0, len_en)]}"

    # передаем данные для запуска тестирования
    new_inKbBtn, msg = en_test(msg, "ruen_start", en_true)
    await bot.send_message(call.message.chat.id, msg, reply_markup = new_inKbBtn)

@dp.callback_query_handler(text=["ru_to_en_test"])
async def call_back_ru(call: types.CallbackQuery):
    """
    This handler will be called when user sends `/ru_to_en_test` command
    """
    global user_en_true
    user_en_true.update({call.message.chat.id: False})
    en_true = user_en_true.get(call.message.chat.id)

    print(f"RU_to_en_test                en_true = {en_true}")

    print('==================================================   ru_to_en_test')
    print(call)
    print("==================================================")
    msg = "Начинаем тестирование! \nRU to EN"
    await bot.send_message(call.message.chat.id, msg)

    # генерируем случайное слово из словоря EN
    msg = f"{en[random.randint(0, len_en)]}"

    # передаем данные для запуска тестирования
    new_inKbBtn, msg = en_test(msg, "enru_start", en_true)
    await bot.send_message(call.message.chat.id, msg, reply_markup = new_inKbBtn)

@dp.callback_query_handler(text=["help"])
async def call_back_help(call: types.CallbackQuery):
    """
    This handler will be called when user sends `/help` command
    """
    # print("==================================================   help")
    # print(call)
    # print("==================================================")
    msg = help_msg
    await bot.send_message(call.message.chat.id, msg)

@dp.callback_query_handler()
async def call_back_other(call: types.CallbackQuery):
    print("================================================== call 1")
    global user_en_true
    # user_en_true.update({call.message.chat.id: True})
    en_true = user_en_true.get(call.message.chat.id)
    
    msg = call.message.text     # слово
    data = call.data            # перевод
    print(f"call.message.text   = {call.message.text}")
    print(f"call.data           = {call.data}")
    print(f"en_true             = {en_true}")
    
    new_inKbBtn, msg_new, msg_old = en_test(msg, data, en_true)
    
    await call.message.edit_text(msg_old)
    await bot.send_message(call.message.chat.id, msg_new, reply_markup = new_inKbBtn)
    print("================================================== call 2")

####################################################################################################

@dp.message_handler(commands=["start"])
async def start_command(message: types.Message):
    """
    This handler will be called when user sends `/start` command
    """
    add_userdb( message.chat.id,
                message.chat.first_name,
                message.chat.last_name,
                message.chat.username,
                message.date
                )
    global user_en_true
    try:
        pass
        if user_en_true.get(message.chat.id) == None:
            print(f"user_en_true.get(message.chat.id) = {user_en_true.get(message.chat.id)}")
            user_en_true = {message.chat.id: False}
            # en_true = user_en_true.get(call.message.chat.id)
        else:
            print(f"user_en_true.get(message.chat.id) = {user_en_true.get(message.chat.id)}")
            user_en_true.update({message.chat.id: False})
    except Exception as ex:
        print('================================================== start Exception1')
        print(ex)
        print('================================================== start Exception2')
    finally:
        pass
        print('================================================== start finally')
        print(str(user_en_true))
        print('================================================== start finally')

    
    msg = f"Привет {message.chat.first_name}!\nПоехали изучать английские слова 😉"
    print('================================================== start command1')
    print(message)
    print('================================================== start command2')
    await bot.send_message(message.chat.id, msg, reply_markup = kb.inKbMkp_start)

@dp.message_handler(commands=["help"])
async def help_command(message: types.Message):
    """
    This handler will be called when user sends `/help` command
    """
    msg = help_msg
    await bot.send_message(message.chat.id, msg)

@dp.message_handler(commands=["admin"])
async def start_command(message: types.Message):
    """
    This handler will be called when user sends `/admin` command
    """
    print(f"message.from_user.id = {message.from_user.id}           admin_id = {admin_id}")
    if message.from_user.id == admin_id:
        try:
            print("admin - Подключаемся к БД")
            conn = sqlite3.connect(bd_name) # соединяемся с БД
            cursor = conn.cursor()  # создаем курсор - это объект, который делает запросы и получает их результат

            # проверяем, существует такой пользователь в базе или нет 
            sql = (f"SELECT * FROM users") # наш SQL запрос к базе данных - вытаскиваем все данные
            
            # print("start - обращаемся к таблице USERS есть ли такой пользователь в базе?")
            cursor.execute(sql)
            
            all_result = cursor.fetchall()
            # print(f"all_result = {all_result}")
            print('===')
            users_count = len(all_result)
            print(users_count)

            msg = f"Количество пользователей: {users_count}\n\n"

            for usr in all_result:
                print(usr)
                msg = msg + str(usr) + "\n"



            
            # user = (id, first_name, last_name, username, date) # Данные пользователя для добавления в БД
            # sql =   (f"INSERT INTO users VALUES (?, ?, ?, ?, ?);") # наш SQL запрос к базе данных
            # cursor.execute(sql, user) 
            conn.commit()
            # print("start - Такого пользователя ещё нет в БД, добавим его    2 ")

            
            pass
        except Exception as Ex:
            # Добавление нового пользователя в БД
            print(Ex)
        finally:
            print("================================================== 1 admin finally")
            conn.close()
            print("admin - conn.close")
    else:
        print('Не равно')

    
    # msg = f"Привет Admin 😉\nТвой id = {message.from_user.id}"
    print('================================================== admin command1')
    print(message)
    print('================================================== admin command2')
    await bot.send_message(message.from_user.id, msg)#, reply_markup = kb.inKbMkp_start)

@dp.message_handler()
async def other_command(message: types.Message):
    """
    This handler will be called when user sends other command
    """
    msg = '@dp.message_handler()'
    print(msg)
    print("==================================================   message")
    print(message)
    print("==================================================")
    
    # await bot.send_message(chat_id, msg)

####################################################################################################

def rnd():
    return random.randint(0, len_en)

"""     Генерируем новую клавиатуру.     """
def createKb(en_true):
    pass
    btns = {}

    # генерирую случайные индексы - это будут случайные слова из словаря
    indexes = [rnd(),rnd(),rnd(),rnd(),rnd(),rnd()]

    print(indexes)
   

    # очищаем кнопочки если есть
    btns.clear()

    # проверяем чего там нагенерили
    # for i in indexes:
    #     print(f"i = {i}, en[i] = {en[i]}, ru[i] = {ru[i]}")

    if en_true: # если en_true = True - английское слово изучаем, генерим русские кнопочки
        btn1 = InlineKeyboardButton(f"{ru[indexes[0]]}", callback_data=f"{indexes[0]},{indexes[0]}")
        btn2 = InlineKeyboardButton(f"{ru[indexes[1]]}", callback_data=f"{indexes[1]},{indexes[0]}")
        btn3 = InlineKeyboardButton(f"{ru[indexes[2]]}", callback_data=f"{indexes[2]},{indexes[0]}")
        btn4 = InlineKeyboardButton(f"{ru[indexes[3]]}", callback_data=f"{indexes[3]},{indexes[0]}")
        btn5 = InlineKeyboardButton(f"{ru[indexes[4]]}", callback_data=f"{indexes[4]},{indexes[0]}")
        btn6 = InlineKeyboardButton(f"{ru[indexes[5]]}", callback_data=f"{indexes[5]},{indexes[0]}")
        
        # сохраняем одно EN солово для вывода в сообщении - будем его разгадывать
        msg = en[indexes[0]]
    
    else: # если lesson_en_true = False - русские слово изучаем, генерим английские кнопочки
        btn1 = InlineKeyboardButton(f"{en[indexes[0]]}", callback_data=f"{indexes[0]},{indexes[0]}")
        btn2 = InlineKeyboardButton(f"{en[indexes[1]]}", callback_data=f"{indexes[1]},{indexes[0]}")
        btn3 = InlineKeyboardButton(f"{en[indexes[2]]}", callback_data=f"{indexes[2]},{indexes[0]}")
        btn4 = InlineKeyboardButton(f"{en[indexes[3]]}", callback_data=f"{indexes[3]},{indexes[0]}")
        btn5 = InlineKeyboardButton(f"{en[indexes[4]]}", callback_data=f"{indexes[4]},{indexes[0]}")
        btn6 = InlineKeyboardButton(f"{en[indexes[5]]}", callback_data=f"{indexes[5]},{indexes[0]}")
        
        # сохраняем одно RU солово для вывода в сообщении - будем его разгадывать
        msg = ru[indexes[0]]

    # Задаем настройки для клавиатуры, изменяемый размер и ширина в 3 кнопки
    inKbMkp_new = InlineKeyboardMarkup(resize_keyboard=True, row_width=3)

    # перемешиваем кнопочки
    btn1, btn2, btn3, btn4, btn5, btn6 = btn_shuffle(btn1, btn2, btn3, btn4, btn5, btn6)

    # заполняем разметку кнопками
    inKbMkp_new.add(btn1, btn2, btn3, btn4, btn5, btn6)

    # возвращаем готовую клавиатуру и msg с изучаемым словом
    return inKbMkp_new, msg

"""     Перемешиваю кнопочки    """
def btn_shuffle(i1,i2,i3,i4,i5,i6):
    pass
    print("btn_shuffle")
    items = {1: i1, 2:i2, 3:i3, 4:i4, 5:i5, 6:i6}
    # print(f"items.items() = {items.items()}")
    # print(f"len(items) = {len(items)}")

    # print()
    # print("items")
    # print(i1,i2,i3,i4,i5,i6)


    lst = []
    lst.append(1)
    lst.append(2)
    lst.append(3)
    lst.append(4)
    lst.append(5)
    lst.append(6)

    # print(f"lst1 = {lst}")
    # print()

    start_i = 0

    random.shuffle(lst)
    # print(f"lst2 = {lst}")
    # print()

    # print(f"items 0 = {items}")

    new_i1 = items.pop(lst[1])
    new_i2 = items.pop(lst[2])
    new_i3 = items.pop(lst[3])
    new_i4 = items.pop(lst[4])
    new_i5 = items.pop(lst[5])
    new_i6 = items.pop(lst[0])

    # print()
    # print("new_items 2")
    # print(new_i1, new_i2, new_i3, new_i4, new_i5, new_i6)

    # return i1,i2,i3,i4,i5,i6
    return new_i1, new_i2, new_i3, new_i4, new_i5, new_i6

"""     Находим правильный ответ и собираем строку ответа   """
def sravnivaem_otveti(msg, data, en_true):
    
    pass # проверяем ответы
    print("проверяем ответы")
    print(f" msg    = {msg}")
    print(f" data   = {data}") # id слова в списке
    print()
    print(f"en_true = {en_true}")

    id0, id1 = data.split(",")
    id0 = int(id0)
    id1 = int(id1)
    print(f" id0 = {id0}            id1 = {id1}")

    
    if en_true:
        print("EN")
        msg_id0              = en[id0]    # на английском
        msg_id0_translate    = ru[id0]    # на русском
        msg_id1              = en[id1]    # на английском
        msg_id1_translate    = ru[id1]    # на русском
    else:
        print("RU")
        msg_id0              = ru[id0]    # на русском
        msg_id0_translate    = en[id0]    # на английском
        msg_id1              = ru[id1]    # на русском
        msg_id1_translate    = en[id1]    # на английском



    # print(f"ru.index(data) = {r}")
    # print(f"en.index(msg) = {e}")
    

    


    # ❗️ ‼️ 
    if msg == msg_id0:
        print(f"msg = {msg}         msg_id0 = {msg_id0}           data = {data}")
        print(f'✅  lesson.en_true = {en_true}')
        msg_old = f"✅ {msg_id0} - {msg_id0_translate}"
    else:
        print(f"msg = {msg}         msg_id0 = {msg_id0}           data = {data}")
        print('❌')
        msg_old = f"‼️ \n✔️ {msg_id0} - {msg_id0_translate} \n✔️ {msg_id1} - {msg_id1_translate}"
    
    return msg_old

"""     Основная функция тестирования   """
def en_test(msg, data, en_true):
    pass
    if data == 'enru_start':
        pass # запускаем инициализацию тестирования с английского на русский
        print(f"start enru_start testing ================================================== en-ru")

        # генерируем клавиатуру для сообщения. 
        # Генерим дополнительные слова и создаем кнопки, 
        # соединяем все это в одну клавиатуру
        inKbBtn, msg = createKb(en_true)
        return inKbBtn, msg
    

    if data == 'ruen_start':
        pass # запускаем инициализацию тестирования с русского на английский
        print(f"start ruen_start testing ================================================== ru-en")
        inKbBtn, msg = createKb(en_true)
        return inKbBtn, msg

    # проверяем ответы
    # sravnivaem_otveti(msg, data)

    # else:
    old_msg = sravnivaem_otveti(msg, data, en_true)
    inKbBtn, msg = createKb(en_true)
        
    return inKbBtn, msg, old_msg # 

"""     Добавлем пользователя в базу данных """
def add_userdb(id, first_name, last_name, username, date):
    try:
        print("start - Подключаемся к БД")
        conn = sqlite3.connect(bd_name) # соединяемся с БД
        cursor = conn.cursor()  # создаем курсор - это объект, который делает запросы и получает их результат

        # проверяем, существует такой пользователь в базе или нет 
        sql =   (f"SELECT * FROM users WHERE userid = {id} ") # наш SQL запрос к базе данных
        
        print("start - обращаемся к таблице USERS есть ли такой пользователь в базе?")
        cursor.execute(sql)
        
        one_result = cursor.fetchone()
        print(f"one_result = {one_result}")
        
        if one_result != None:
            pass
            print("start - Такой пользователь есть в БД")
        else:
            print("start - Такого пользователя ещё нет в БД, добавим его")
            user = (id, first_name, last_name, username, date) # Данные пользователя для добавления в БД
            sql =   (f"INSERT INTO users VALUES (?, ?, ?, ?, ?);") # наш SQL запрос к базе данных
            cursor.execute(sql, user) 
            conn.commit()
            print("start - Такого пользователя ещё нет в БД, добавим его    2 ")

        
        pass
    except Exception:
        # Добавление нового пользователя в БД
        print(f"================================================== start except")
        print("start - Такого пользователя ещё нет в БД, добавим его")
        user = (id, first_name, last_name, username, date) # Данные пользователя для добавления в БД
        sql =   (f"INSERT INTO users VALUES (?, ?, ?, ?, ?);") # наш SQL запрос к базе данных
        cursor.execute(sql, user) 
        conn.commit()
        

    finally:
        print("================================================== 1 start finally")
        conn.close()
        print("start - conn.close")

"""     Стартовая функция. Создаем базу если её нету и подготавливаем таблицы.  """
def on_start():
    pass
    print('main start')
    try:    # если файл бд нету, оповещаем что создадим файли и запишем структуру таблицы
        print("Подключаемся к БД")
        conn = sqlite3.connect(bd_name) # соединяемся с БД
        cursor = conn.cursor()  # создаем курсор - это объект, который делает запросы и получает их результат
        
        # составляем запрос к базе данных для создания таблицы
        sql =   ("""CREATE TABLE IF NOT EXISTS users(
                   userid INT PRIMARY KEY,
                   first_name TEXT,
                   last_name TEXT,
                   username TEXT,
                   registration_date TEXT);
                """)

        print("Записываю структуру таблицы USERS в БД если её не существует")
        cursor.execute(sql) # 
        conn.commit()
    except Exception:
        print(f"exeption: {Exception}\n==================================================")
    finally:
        print("================================================== main - finish")
        conn.close()
    
   




####################################################################################################

if __name__ == '__main__':
    on_start()
    executor.start_polling(dp, skip_updates=True,)# on_startup=on_start)